export default {
  shadow: function(inEl) {
    if (inEl) {
      return inEl.shadowRoot || inEl.webkitShadowRoot;
    }
  },
  canTarget: function(shadow) {
    return shadow && Boolean(shadow.elementFromPoint);
  },
  targetingShadow: function(inEl) {
    var s = this.shadow(inEl);
    if (this.canTarget(s)) {
      return s;
    }
  },
  olderShadow: function(shadow) {
    var os = shadow.olderShadowRoot;
    if (!os) {
      var se = shadow.querySelector('shadow');
      if (se) {
        os = se.olderShadowRoot;
      }
    }
    return os;
  },
  allShadows: function(element) {
    var shadows = [];
    var s = this.shadow(element);
    while (s) {
      shadows.push(s);
      s = this.olderShadow(s);
    }
    return shadows;
  },
  searchRoot: function(inRoot, x, y) {
    if (inRoot) {
      var t = inRoot.elementFromPoint(x, y);
      var st, sr;

      // is element a shadow host?
      sr = this.targetingShadow(t);
      while (sr) {

        // find the the element inside the shadow root
        st = sr.elementFromPoint(x, y);
        if (!st) {

          // check for older shadows
          sr = this.olderShadow(sr);
        } else {

          // shadowed element may contain a shadow root
          var ssr = this.targetingShadow(st);
          return this.searchRoot(ssr, x, y) || st;
        }
      }

      // light dom element is the target
      return t;
    }
  },
  owner: function(element) {
    var s = element;

    // walk up until you hit the shadow root or document
    while (s.parentNode) {
      s = s.parentNode;
    }

    // the owner element is expected to be a Document or ShadowRoot
    if (s.nodeType !== Node.DOCUMENT_NODE && s.nodeType !== Node.DOCUMENT_FRAGMENT_NODE) {
      s = document;
    }
    return s;
  },
  findTarget: function(inEvent) {
    var x = inEvent.clientX;
    var y = inEvent.clientY;

    // if the listener is in the shadow root, it is much faster to start there
    var s = this.owner(inEvent.target);

    // if x, y is not in this root, fall back to document search
    if (!s.elementFromPoint(x, y)) {
      s = document;
    }
    return this.searchRoot(s, x, y);
  }
};
